package com.masonluo.mlonlinejudge.controller;

import com.masonluo.mlonlinejudge.constant.SystemConstant;
import com.masonluo.mlonlinejudge.mapper.ProblemMapper;
import com.masonluo.mlonlinejudge.model.bo.ProblemBo;
import com.masonluo.mlonlinejudge.model.bo.SelectProblemBo;
import com.masonluo.mlonlinejudge.model.dto.ProblemUploadDto;
import com.masonluo.mlonlinejudge.model.dto.TestCaseUploadDto;
import com.masonluo.mlonlinejudge.model.param.ProblemParam;
import com.masonluo.mlonlinejudge.model.param.ProblemUploadParam;
import com.masonluo.mlonlinejudge.model.param.SelectProblemParam;
import com.masonluo.mlonlinejudge.model.vo.ProblemNameAndIdVo;
import com.masonluo.mlonlinejudge.model.vo.TestCaseUploadVo;
import com.masonluo.mlonlinejudge.result.Result;
import com.masonluo.mlonlinejudge.result.ResultCode;
import com.masonluo.mlonlinejudge.security.Token;
import com.masonluo.mlonlinejudge.service.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.velocity.runtime.directive.Foreach;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.*;

/**
 * @author masonluo
 * @date 2021/2/7 5:33 下午
 */
@Api(description = "应用题模块")
@RestController
@RequestMapping("/problems")
public class ProblemController {

    @Autowired
    private ProblemService problemService;

    @Autowired
    private ProblemMapper problemMapper;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private UserService userService;

    @Autowired
    private SelectProblemService selectProblemService;

    @Autowired
    private TestcaseFileService testcaseFileService;
    @Autowired
    private ProgramAnswerService programAnswerService;

    @Autowired
    private ImportProblemService importProblemService;


    @ApiOperation(value = "根据id修改题目")
    @PatchMapping("/updateProblemById")
    public Result<ProblemParam> updateProblemById(@RequestBody @Valid ProblemBo problemBo, @RequestParam Integer userId, @RequestParam Integer problemId) {
        if (Objects.isNull(problemBo.getId())) {
            throw new IllegalArgumentException("问题不可为空");
        }
        return Result.ok(problemService.updateProblemById(problemBo, userId, problemId));
    }

    @ApiOperation(value = "根据id查找题目")
    @GetMapping("/{problemId}")
    public Result<ProblemParam> findProblemById(@PathVariable("problemId") Integer problemId) {
        if (Objects.isNull(problemId)) {
            throw new IllegalArgumentException("问题ID不可为空");
        }
        return Result.ok(problemService.findById(problemId, true, true));
    }

    @ApiOperation(value = "根据章节id查找该章节下的所有题目")
    @GetMapping
    public Result<List<ProblemNameAndIdVo>> findProblemByIndexId(@RequestParam("indexId") Integer indexId) {
        return Result.ok(problemService.findProblemByIndexId(indexId));
    }

    @ApiOperation(value = "所有应用题题目列表")
    @GetMapping("/list")
    public Result list(@RequestParam("pageNum") Integer pageNum,
                       @RequestParam("pageSize") Integer pageSize) {
        List<ProblemParam> problemParams = problemService.list(pageNum, pageSize);
        return new Result(ResultCode.OK, "题目信息查找成功", problemParams, pageNum, pageSize, problemService.countAll());

    }

   /* @ApiOperation(value = "根据标签/标题/题型搜索题")
    @GetMapping("/searchProblems")
    public Result<List<ProblemParam>> findProblemByOthers(@RequestParam("title") String title,
                                                          @RequestParam("tag") String tag,
                                                          @RequestParam("type") Integer type) {
        return Result.ok(problemService.searchProblems(tag,title,type));
    }*/

    @ApiOperation(value = "获取所有题目列表/根据标签/标题/题型搜索题")
    @GetMapping("/listAllProblem")
    public Result listAllProblem(@RequestParam("pageNum") Integer pageNum,
                                 @RequestParam("pageSize") Integer pageSize,
                                 @RequestParam(value = "title", required = false) String title,
                                 @RequestParam(value = "tag", required = false) String tag,
                                 @RequestParam(value = "type", required = false) Integer type) {
        List<Object> allProblems = problemService.searchAllProblems(tag, title, type, pageNum, pageSize);
        return new Result(ResultCode.OK, "题库查找成功", allProblems, pageNum, pageSize, problemService.countByVar(tag, title, type));
    }

    @ApiOperation(value = "列出所有该用户上传的题目")
    @GetMapping("/list/{userId}")
    public Result listByUserId(@PathVariable("userId") Integer userId,
                               @RequestParam("pageNum") Integer pageNum,
                               @RequestParam("pageSize") Integer pageSize) {
        if (Objects.isNull(userId)) {
            throw new IllegalArgumentException("用户ID不可为空");
        }
        List<ProblemParam> problemParams = problemService.listByUserId(userId, pageNum, pageSize);
        return new Result(ResultCode.OK, "题目查找成功", problemParams, pageNum, pageSize, problemService.countByUserId(userId));
    }


    @ApiOperation(value = "修改测试用例，返回测试用例id")
    @PostMapping("/updateTestCase")
    public Result<TestCaseUploadVo> updateTestCase(@RequestParam("problemId") Integer problemId,
                                                   @RequestParam("testCaseFile") MultipartFile testCaseFile) {

        TestCaseUploadDto dto = null;

        String preTestCaseId = selectProblemService.getTestCaseIdById(problemId);
        if (!programAnswerService.deleteProgramAnswer(preTestCaseId)) {
            throw new IllegalArgumentException("删除原来的输入输出数据失败");
        }
        try {
            //dto = problemService.uploadTestCase(testCaseFile);
            dto = testcaseFileService.sendMultipartFile(testCaseFile);
            if (dto != null && dto.getAnswers() != null) {
                int row = programAnswerService.insertProgramAnswer(dto.getTestCaseId(), dto.getAnswers(),
                        dto.getInputContents(), problemId);
            }
        } catch (IOException e) {
            throw new IllegalArgumentException("Please upload a regular zip file", e);
        }
        assert dto != null;
        String newTestCaseId = dto.getTestCaseId();//新的测试用例
        Result<TestCaseUploadVo> res = new Result<>(ResultCode.OK, "update success", new TestCaseUploadVo(newTestCaseId));

        if (!selectProblemService.updateTestCaseIdById(problemId, newTestCaseId)) {
            throw new IllegalArgumentException("更新编程题的原有测试用例id失败");//更新的是t_problem表中的test_cast_id
        }
        return res;
    }

    @ApiOperation(value = "测试数据上传，返回测试数据id")
    @PostMapping("/testCase")
    public Result<TestCaseUploadVo> uploadTestCase(@RequestParam("testCaseFile") MultipartFile testCaseFile) {
        TestCaseUploadDto dto = null;
        try {
            //dto = problemService.uploadTestCase(testCaseFile);
            dto = testcaseFileService.sendMultipartFile(testCaseFile);
            if (dto != null && dto.getAnswers() != null) {
                int row = programAnswerService.insertAnswer(dto.getTestCaseId(), dto.getAnswers(), dto.getInputContents());
            }
        } catch (IOException e) {
            throw new IllegalArgumentException("Please upload a regular zip file", e);
        }
        Result<TestCaseUploadVo> res = new Result<>(ResultCode.CREATED, "upload success", new TestCaseUploadVo(dto.getTestCaseId()));
        return res;
    }

    @ApiOperation(value = "下载测试用例")
    @PostMapping("/downloadTestCase")
    public void downloadTestCase(@RequestParam("testCaseId") String testCaseId,HttpServletRequest request, HttpServletResponse response){
            try {
                testcaseFileService.downloadTestCase(testCaseId,request,response);
            } catch (Exception e) {
                throw new IllegalArgumentException("下载测试用例失败");
            }
    }


    @ApiOperation(value = "上传一个题目")
    @PostMapping
    @SuppressWarnings("uncheck")
    public Result<ProblemParam> uploadProblem(@RequestBody ProblemUploadParam problem, HttpServletRequest request) {
        if (Objects.isNull(problem)) {
            throw new IllegalArgumentException("问题不可为空");
        }
        if (Objects.isNull(problem.getUserId())) {
            throw new IllegalArgumentException("userId不可为空");
        }
        ProblemUploadDto dto = problemMapper.uploadParamToUploadDto(problem);
        // TODO 测试用，之后恢复正常逻辑
        /*String tokenStr = request.getHeader(SystemConstant.TOKEN_HEADER);
        dto.setUserId(acquireUserIdFromToken(tokenStr));*/
        ProblemParam res = problemService.uploadProblem(dto);
        if (res != null && res.getTestCaseId() != null) {//更新t_program_answer表，加入题目的id
            int row = programAnswerService.updateAnswer(res.getTestCaseId(), res.getId());
        }
        return new Result<ProblemParam>(ResultCode.CREATED, "success upload problem", res);
    }

    @ApiOperation(value = "根据id删除题目")
    @DeleteMapping("/{problemId}")
    @SuppressWarnings("rawtypes")
    public Result delete(@PathVariable("problemId") Integer problemId) throws Exception {
        if (Objects.isNull(problemId)) {
            throw new IllegalArgumentException("问题ID不可为空");
        }
        problemService.delete(problemId);
        return Result.ok();
    }

    @ApiOperation(value = "上传文件批量导入编程题")
    @PostMapping(value = "/import", headers = "content-type=multipart/form-data")
    public Result importProblem(@RequestParam(value = "file") MultipartFile file) throws IOException {
        importProblemService.importProblem(file);
        return Result.ok();
    }

    @ApiOperation(value = "根据难度等级返回编程题")
    @GetMapping("/listByDifficulty")
    public Result listAllProblemByDifficulty(@RequestParam("difficulty")String difficulty,
                                             @RequestParam("pageNum") Integer pageNum,
                                             @RequestParam("pageSize") Integer pageSize){
        List<ProblemParam> problemParams = problemService.listAllProblemByDifficulty(difficulty,pageNum,pageSize);
        return new Result(ResultCode.OK, "题目信息查找成功", problemParams, pageNum, pageSize, problemService.countByDifficulty(difficulty));

    }


    private Integer acquireUserIdFromToken(String tokenStr) {
        Token token = tokenService.convert(tokenStr);
        return userService.findIdByUsername(token.getUsername());
    }

    public ProblemService getProblemService() {
        return problemService;
    }

    public void setProblemService(ProblemService problemService) {
        this.problemService = problemService;
    }

    public ProblemMapper getProblemMapper() {
        return problemMapper;
    }

    public void setProblemMapper(ProblemMapper problemMapper) {
        this.problemMapper = problemMapper;
    }

    public TokenService getTokenService() {
        return tokenService;
    }

    public void setTokenService(TokenService tokenService) {
        this.tokenService = tokenService;
    }

    public UserService getUserService() {
        return userService;
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }
}
